package controllers;

import co.edu.unal.satacredito.database.exception.UnreachableHostException;
import co.edu.unal.satacredito.database.connection.NotSyntaxDatastoreFactory;
import co.edu.unal.satacredito.database.dao.NotSyntaxTransactionMongoDao;
import co.edu.unal.satacredito.database.entity.NotSyntaxTransaction;
import co.edu.unal.satacredito.transactions.queuewriter.QueueWriter;
import co.edu.unal.satacredito.transactions.queuewriter.entity.TransactionPojo;
import com.google.code.morphia.Datastore;
import dao.ArchiveDAO;
import dao.DocumentTypeDAO;
import dao.FranchiseDAO;
import dao.TraceStateDAO;
import entities.*;
import facade.facadeClass;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;



import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.bson.types.ObjectId;
import service.MD5Service;
import java.util.Date;
import ws.filelog.HeaderFile;

/**
 * @author Sergio Perez 257605
 */
public class SyntacticValidator {

    private DocumentTypeDAO documentTypeDAO;
    private TraceStateDAO traceStateDao;
    private FranchiseDAO franchiseDAO;
    private Trace entityTrace;
    private Archive entityArchive;
    private DocumentType entityDocumentType;
    private Franchise entityFranchise;
    private TraceState entityTraceState;
    private String[] tempTrace;
    private String checkTrace;
    private String checkSum;
    private facadeClass fc;
    private long transactionLine;

    /**
     * valida la traza
     *
     * @param theString la traza a ser validada
     */
    public boolean validate(String theString, Archive archive, int idTransaction) throws UnknownHostException, IOException, ParseException, UnreachableHostException {

        String delimiter = "\\|";
        tempTrace = theString.split(delimiter);
        boolean valid = true;

        if (tempTrace.length != 9) {
            //System.out.println("overall");
            valid = false;
        }

        for (int i = 0; i < tempTrace.length; i++) {
            if (tempTrace[i].equals("")) {
                //System.out.println("null");
                valid = false;
            }
        }
        if (!tempTrace[0].matches("CC|CE")) {//document type
            //System.out.println("0");
            valid = false;
        }
        if (!tempTrace[1].matches("^\\d{4,10}$")) {//document number
            //System.out.println("1");
            valid = false;
        }
        if (!tempTrace[2].matches("^[a-zA-Z ]+$")) {//card owner
            //System.out.println("2");
            valid = false;
        }
        if (!tempTrace[3].matches("CREDITO|DEBITO")) {//card type
            //System.out.println("3");
            valid = false;
        }
        if (!tempTrace[4].matches("^\\d{0,16}$")) {//card number
            //System.out.println("4");
            valid = false;
        }
        String[] cardVendors = {"AMEX", "VISA", "MC"};//list of franchises
        String finalStrFr = "";//list of frachises on a string
        for (String vend : cardVendors) {
            finalStrFr += vend + "|";
        }
        finalStrFr = finalStrFr.substring(0, finalStrFr.length() - 1);
        //System.out.println(finalStrFr);
        if (!tempTrace[5].matches(finalStrFr)) {//card franchise
            //System.out.println("5");
            valid = false;
        }
        if (!tempTrace[6].matches("^\\d+$")) {//purchased ammount
            //System.out.println("6");
            valid = false;
        }
        if (!tempTrace[7].matches("^[a-zA-Z ]+$")) {//purchase description
            //System.out.println("7");
            valid = false;
        }
        if (!tempTrace[8].matches("^[012]\\d:[012345]\\d [0123]\\d/[01]\\d/\\d{4}$")) {//purchase date
            //System.out.println("8");
            valid = false;
        }

        checkTrace = tempTrace[0] + tempTrace[1] + tempTrace[2] + tempTrace[3] + tempTrace[4] + tempTrace[5] + tempTrace[6] + tempTrace[7] + tempTrace[8];
        MD5Service md5 = new MD5Service();
        checkSum = md5.getMD5(checkTrace);

        if (valid) {
            //sendValidTrace();
            persistValidOnDB(idTransaction, archive);
        } else {
            //sendInvalidTrace();
            //persisInvalidOnDB(idTransaction);
        }
        return valid;
    }

    public boolean persistValidOnDB(int idTransaction, Archive archive) {
        traceStateDao = new TraceStateDAO();
        franchiseDAO = new FranchiseDAO();
        documentTypeDAO = new DocumentTypeDAO();
        ArchiveDAO archiveDAO = new ArchiveDAO();

        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("satacreditoclientePU");
        EntityManager em;
        fc = new facadeClass(); 
        //em = emf.createEntityManager();
        em = fc.getEntityManager();
        
        em.getTransaction().begin();

        archive = archiveDAO.searchByIdMongi(em, archive.getIdMongo());
        System.out.println("ID MONGO :"+archive.getIdMongo());
        entityTraceState = traceStateDao.searchById(em, 1);
        entityDocumentType = documentTypeDAO.searchByName(em, tempTrace[0]);
        entityFranchise = franchiseDAO.searchByName(em, tempTrace[5]);
        

        
        entityTrace = new Trace(archive, checkSum, entityTraceState, entityFranchise,
                entityDocumentType, idTransaction, Integer.valueOf(tempTrace[1]),
                tempTrace[2], tempTrace[3], tempTrace[4], Long.valueOf(tempTrace[6]),
                tempTrace[7], tempTrace[8]);
        entityTrace.setArchivoIdMondo(archive.getIdMongo());
        fc.create(entityTrace);
        em.getTransaction().commit();
        return true;
    }

    private void persisInvalidOnDB(int idTransaction) {
    }

    public boolean sendValidTrace() throws IOException, ParseException {
        //Rubiano aquí debe poner la instrucción para el envío a la cola.
        //Debe hacerlo con lo que hizo Oscar.
        TransactionPojo txp;
        QueueWriter qw = new QueueWriter();
        Trace tr = new Trace();

        DateFormat formatter;
        formatter = new SimpleDateFormat("dd-MMM-yy");

        txp = new TransactionPojo();
        txp.setCardNumber("" + tr.getDNI());
        txp.setCardType(Integer.parseInt(tr.getCardType()));
        txp.setFileId(new ObjectId("" + tr.getArchivoIdMondo()));
        txp.setFranchise(new ObjectId("" + tr.getFranchise()));
        txp.setLastname("-");
        txp.setMiddlename("-");
        txp.setName("NAME");
        txp.setNin("" + tr.getDNI());
        txp.setNinType(tr.getDocumenType().getIdDocumentType());
        txp.setPurchaseAmount(tr.getValueTransaction());
        txp.setPurchaseDate((Date) formatter.parse(tr.getDate()));
        txp.setPurchaseDetail(tr.getDescription());
        txp.setTransactionId(new ObjectId("" + tr.getIdTrace()));

        qw.QueueWriter(txp);

        return true;
    }

    public boolean sendInvalidTrace() throws UnknownHostException, UnreachableHostException {
        //host: 200.119.14.253 puerto : 27017
         Datastore datastore = NotSyntaxDatastoreFactory.createDatastore();
         NotSyntaxTransaction transactionOut = new NotSyntaxTransaction();      
         NotSyntaxTransactionMongoDao dao = new NotSyntaxTransactionMongoDao(datastore);

         transactionOut.setBrand(null);
         transactionOut.setEstablishment(null);
         transactionOut.setFileId(null);
         transactionOut.setTransactionId(null);
         transactionOut.setTransactionLine(transactionLine);
         transactionOut.setValidationDate(null);

         dao.create(transactionOut);

        return true;
    }

    public Archive getArchive(String filePath, String idEstablishment, String idBrand) {
        final EntityManagerFactory emf = Persistence.createEntityManagerFactory("satacreditoclientePU");
        EntityManager em;
        em = emf.createEntityManager();
        ArchiveDAO archiveDAO = new ArchiveDAO();
        FileLogServiceControl control = new FileLogServiceControl();
        String header = control.headerFile(idEstablishment, idBrand);

        Date dateToDay = new Date();
        java.sql.Date date = new java.sql.Date(dateToDay.getYear(), dateToDay.getMonth(), dateToDay.getDay());
        entityArchive = new Archive(header, idBrand, idEstablishment, 0, 0, filePath, date, date, 0, 0);

        em.getTransaction().begin();
        archiveDAO.create(em, entityArchive);
        em.getTransaction().commit();
        return entityArchive;
    }
    
}

